package mes.kanban.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.web.util.WebUtils;
import org.crazycake.shiro.RedisSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import mes.kanban.entity.MesPermission;
import mes.kanban.entity.MesRole;
import mes.kanban.service.UserMessageServiceI;
import mes.kanban.util.IsNotNullValit;
import mes.kanban.vo.MesUserVO;

/**
 * 
 * @author gjy
 *
 * 2018年2月11日上午11:36:22
 */
public class MyShiroRealm extends AuthorizingRealm {
	
	
	private static final Logger log = LoggerFactory.getLogger(MyShiroRealm.class);

	
    @Resource
    private UserMessageServiceI userMessageServiceI;
    
    @Autowired
    private RedisSessionDAO redisSessionDAO;
    
    private String algorithmName;
    
    private int hashIterations;
    
    @Value("${shiro.securityManage.timeout}")
	private int shiroTimeout;
    
    public MyShiroRealm() {
    	super();
	}
    
    public MyShiroRealm(String algorithmName, int hashIterations) {
		this.algorithmName = algorithmName;
		this.hashIterations = hashIterations;
	}

	/*主要是用来进行身份认证的，也就是说验证用户输入的账号和密码是否正确。*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        log.info("MyShiroRealm.doGetAuthenticationInfo()");
        //获取用户的输入的账号.
        String userCode = (String)token.getPrincipal();
        log.info(token.getCredentials()+"");
        /*
         * 通过username从数据库中查找 User对象
         * 
         * 这里可以根据实际情况做缓存，如果不做，Shiro自己也是有时间间隔机制，2分钟内不会重复执行该方法
         * 
         */
        MesUserVO userInfo = userMessageServiceI.findUsersByCodeForShiro(userCode);
        
        if(userInfo == null){
            return null;
        }else if(userInfo.getStatus() == -1) {
        	throw new LockedAccountException();
        } else{
        	//如果密码加密功能启用以后，需要取消这个加密的操作
        	encryptPassword(userInfo);
		}
        
        log.info("----->>user is real ="+userInfo);
        
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                userInfo, //用户名
                userInfo.getPassWord(), //密码
                ByteSource.Util.bytes(userInfo.getCredentialsSalt()),//salt=username+salt
                getName()  //realm name
        );
        
     // 当验证都通过后，把用户信息放在session里
        Session session = SecurityUtils.getSubject().getSession();
        //设置超时时间
        session.setTimeout(shiroTimeout);
        
        session.setAttribute(KVRedisConfig.SESSION_ATTRIBUTE_USER.getHaskey(), userInfo);
        session.setAttribute(KVRedisConfig.SESSION_ATTRIBUTE_USERNAME.getHaskey(), userInfo.getUserName());
        session.setAttribute(KVRedisConfig.SESSION_ATTRIBUTE_USERID.getHaskey(), userInfo.getId());
        
        return authenticationInfo;
    }
    
	@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        
//        MesUserVO userInfo =  principals.getPrimaryPrincipal();
        
        Object o = principals.getPrimaryPrincipal();
        
        MesUserVO userInfo = new MesUserVO();
        
        BeanUtils.copyProperties(o, userInfo);
        
        List<MesRole> roles = userInfo.getRoles();
        
        for(int i=0;i<roles.size();i++){
        	
        	MesRole role = new MesRole();
        	
        	BeanUtils.copyProperties(roles.get(i), role);
        	
            authorizationInfo.addRole(role.getRoleName());
        }
        
        List<MesPermission> permissions = userInfo.getPermissions();
        
        for(int i=0;i<permissions.size();i++){
        	
        	MesPermission p = new MesPermission();
        	
        	BeanUtils.copyProperties(permissions.get(i), p);
        	
            authorizationInfo.addStringPermission(p.getUrl());
            
        }
        return authorizationInfo;
    }
    
    public void encryptPassword(MesUserVO user) {
		
        String newPassword = new SimpleHash(algorithmName, user.getPassWord(),  ByteSource.Util.bytes(user.getCredentialsSalt()), hashIterations).toHex();
        user.setPassWord(newPassword);

    }
    
    /**
     * 根据userId 清除当前session存在的用户的权限缓存
     * @param userIds 已经修改了权限的userId
     */
    public void clearUserAuthByUserId(List<String> userIds){
    	
        if(!IsNotNullValit.CollectionIsNotNull(userIds)) {
        	return ;
        }	
        //获取所有session
        Collection<Session> sessions = redisSessionDAO.getActiveSessions();
        //定义返回
        List<SimplePrincipalCollection> list = new ArrayList<SimplePrincipalCollection>();
        
        log.info("存在session条数:"+sessions.size()+" 条");
        
        for (Session session:sessions){
            //获取session登录信息。
            Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            if(null != obj && obj instanceof SimplePrincipalCollection){
                //强转
                SimplePrincipalCollection spc = (SimplePrincipalCollection)obj;
                //判断用户，匹配用户ID。
                obj = spc.getPrimaryPrincipal();
                if(null != obj && obj instanceof MesUserVO){
                	MesUserVO user = (MesUserVO) obj;
                    log.info("user:"+user);
                    //比较用户ID，符合即加入集合
                    if(null != user && userIds.contains(user.getId())){
                        list.add(spc);
                    }
                }
            }
        }
        RealmSecurityManager securityManager =
                (RealmSecurityManager) SecurityUtils.getSecurityManager();
        MyShiroRealm realm = (MyShiroRealm)securityManager.getRealms().iterator().next();
        for (SimplePrincipalCollection simplePrincipalCollection : list) {
            realm.clearCachedAuthorizationInfo(simplePrincipalCollection);
        }
    }
    
    public void clearAuthz(HttpServletRequest req){  
    	HttpSession session = WebUtils.toHttp(req).getSession();
        String userinfoID = String.valueOf(session.getAttribute("userSessionId"));
        
        List<String> userIds = new ArrayList<String>();
        userIds.add(userinfoID);
        
        this.clearUserAuthByUserId(userIds);
        
    }  
    
}